﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Media;
using System.Windows;
using System.Threading;
using Microsoft.Research.Kinect.Audio;
using System.IO;
using Microsoft.Speech.Recognition;
using Microsoft.Speech.AudioFormat;

namespace Hugo
{
    class Voice
    {
        private static Voice instance;

        public static Voice getInstance()
        {
            if (instance == null)
            {
                instance = new Voice();
            }

            return instance;
        }

        private static bool initialized = false;
        //private static Thread kinectAudioThread;
        //private static KinectAudioSource kinectAudioSource;

        KinectAudioSource kinectSource;
        SpeechRecognitionEngine speechEngine;
        Stream stream;
        string RecognizerId = "SR_MS_en-US_Kinect_10.0";
        bool speechNotRecognized;
        RecognizerInfo rec;
        private Grammar lastGrammar;

        public Voice()
        {
            kinectSource = new KinectAudioSource();

            kinectSource.FeatureMode = true;
            kinectSource.AutomaticGainControl = false;
            kinectSource.SystemMode = SystemMode.OptibeamArrayOnly;

            rec = (from r in SpeechRecognitionEngine.InstalledRecognizers() where r.Id == RecognizerId select r).FirstOrDefault();

            if (rec == null)
            {
                MessageBox.Show(
                    @"Speech recognition failed to initialize. Please make sure you have the Microsoft Speech SDK installed.",
                    "Unable to use speech recognition",
                    MessageBoxButton.OK,
                    MessageBoxImage.Error);
                return;
            }

            speechEngine = new SpeechRecognitionEngine(rec.Id);

            var choices = new Choices();
            choices.Add("Help");

            GrammarBuilder gb = new GrammarBuilder();
            gb.Culture = rec.Culture;
            gb.Append(choices);

            var g = new Grammar(gb);
            speechEngine.LoadGrammar(g);
            
            speechEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(sre_SpeechRecognized);
            speechEngine.RecognizerUpdateReached += new EventHandler<RecognizerUpdateReachedEventArgs>(recognizer_RecognizerUpdateReached);

            Console.WriteLine("Recognizing Speech");

            stream = kinectSource.Start();

            speechEngine.SetInputToAudioStream(stream,
                          new SpeechAudioFormatInfo(
                              EncodingFormat.Pcm, 16000, 16, 1,
                              32000, 2, null));

            speechEngine.RecognizeAsync(RecognizeMode.Multiple);
        }

        private static RecognizerInfo GetKinectRecognizer()
        {
            Func<RecognizerInfo, bool> matchingFunc = r =>
            {
                string value;
                r.AdditionalInfo.TryGetValue("Kinect", out value);
                return "True".Equals(value, StringComparison.InvariantCultureIgnoreCase) && "en-US".Equals(r.Culture.Name, StringComparison.InvariantCultureIgnoreCase);
            };
            return SpeechRecognitionEngine.InstalledRecognizers().Where(matchingFunc).FirstOrDefault();
        }


        void sre_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            if (e.Result.Confidence >= 0.85)
            {

                //Sounds.speakMessage("I heard: " + e.Result.Text);
                MainWindow.getInstance().getCurrentPage().respondToRecognizedVoiceCommand(e.Result.Text);

                /*
                foreach (Image target in currentPage().pathListBox.Items)
                {
                    String option = target.Tag.ToString();
                    if (option.Contains(e.Result.Text))
                    {
                        MouseButtonEventArgs me = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left, null);
                        me.RoutedEvent = Mouse.MouseUpEvent;
                        target.RaiseEvent(me);
                        break;
                    }
                }
                 */
            }
        }

        /*
        private void StartKinectAudioStream()
        {
            kinectAudioSource = new KinectAudioSource();
            kinectAudioSource.SystemMode = SystemMode.OptibeamArrayOnly;
            kinectAudioSource.FeatureMode = true;
            kinectAudioSource.AutomaticGainControl = false;
            var kinectStream = kinectAudioSource.Start();
            sre.SetInputToAudioStream(kinectStream, new SpeechAudioFormatInfo(
                                                           EncodingFormat.Pcm, 16000, 16, 1,
                                                           32000, 2, null));
            sre.RecognizeAsync(RecognizeMode.Multiple);
        }
         */

        public void setAcceptableTerms(List<string> AcceptedTerms)
        {
            var choices = new Choices();
            foreach (String s in AcceptedTerms)
            {
                choices.Add(s);
            }

            GrammarBuilder gb = new GrammarBuilder();
            gb.Culture = rec.Culture;
            gb.Append(choices);
            var g = new Grammar(gb);

            if (lastGrammar != null)
            {
                speechEngine.RequestRecognizerUpdate(new UpdateGrammarRequest
                {
                    Engine = this.speechEngine,
                    RequestType = GrammarRequestType.UnloadGrammar,
                    Grammar = lastGrammar
                });
            }
            speechEngine.RequestRecognizerUpdate(new UpdateGrammarRequest
            {
                Engine = this.speechEngine,
                RequestType = GrammarRequestType.LoadGrammar,
                Grammar = g
            });

            lastGrammar = g;
        }

        private class UpdateGrammarRequest
        {
            public GrammarRequestType RequestType;
            public Grammar Grammar;
            public SpeechRecognitionEngine Engine;
        }

        private enum GrammarRequestType { UnloadGrammar, LoadGrammar };

        public static void recognizer_RecognizerUpdateReached(object sender, RecognizerUpdateReachedEventArgs e)
        {
            var request = e.UserToken as UpdateGrammarRequest;
            if (request == null)
                return;

            switch (request.RequestType)
            {
                case GrammarRequestType.LoadGrammar:
                    request.Engine.LoadGrammar(request.Grammar);
                    break;
                case GrammarRequestType.UnloadGrammar:
                    request.Engine.UnloadGrammar(request.Grammar);
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }


    }
}
